package xxl.robotlegs.extensions.viewmanager.impl 
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;
	import xxl.signals.impl.natives.sets.DisplayObjectSignalSet;
	/**
	 * ...
	 * @author XXL
	 */
	public class StageObserver 
	{
		private const _filter:RegExp = /^mx\.|^spark\.|^flash\./;
		private const signalSetDic:Dictionary = new Dictionary(true);
		private var _registry:ContainerRegistry;
		
		public function StageObserver(containerRegistry:ContainerRegistry) 
		{
			_registry = containerRegistry;
			_registry.signal.addToMap(ContainerRegistrySignal.ROOT_CONTAINER_ADD, onRootContainerAdd);
			_registry.signal.addToMap(ContainerRegistrySignal.ROOT_CONTAINER_REMOVE, onRootContainerRemove);
			
			const rootBindings:Vector.<ContainerBinding> = _registry.rootBindings;
			for (var i:int = rootBindings.length; i--; )
			{
				addRootListener(rootBindings[i].container);
			}
		}
		
		public function destroy():void
		{
			_registry.signal.removeFromMap(ContainerRegistrySignal.ROOT_CONTAINER_ADD, onRootContainerAdd);
			_registry.signal.removeFromMap(ContainerRegistrySignal.ROOT_CONTAINER_REMOVE, onRootContainerRemove);
			const rootBindings:Vector.<ContainerBinding> = _registry.rootBindings;
			for (var i:int = rootBindings.length; i--; )
			{
				removeRootListener(rootBindings[i].container);
			}
		}
		
		//----------private
		
		private function onRootContainerAdd(type:String, container:DisplayObjectContainer):void
		{
			addRootListener(container);
		}
		
		private function onRootContainerRemove(type:String, container:DisplayObjectContainer):void
		{
			removeRootListener(container);
		}
		
		private function addRootListener(container:DisplayObjectContainer):void
		{
			if (!signalSetDic[container])
			{
				signalSetDic[container] = new DisplayObjectSignalSet(container);
			}
			const signalSet:DisplayObjectSignalSet = signalSetDic[container];
			signalSet.addedToStage_Capture.add(onViewAddedToStage);
			signalSet.addedToStage.addOnce(onContainerRootAddedToStage);
		}
		
		private function removeRootListener(container:DisplayObjectContainer):void
		{
			const signalSet:DisplayObjectSignalSet = signalSetDic[container];
			signalSet && signalSet.removeAll();
			delete signalSetDic[container];
		}
		
		private function onViewAddedToStage(e:Event):void
		{
			const view:DisplayObject = e.target as DisplayObject;
			const qcn:String = getQualifiedClassName(view);
			const filtered:Boolean = _filter.test(qcn);
			if (filtered)
			{
				return;
			}
			const type:Class = view["constructor"];
			var binding:ContainerBinding = _registry.findParentBinding(view);
			while (binding)
			{
				binding.handleView(view, type);
				binding = binding.parent;
			}
		}
		
		private function onContainerRootAddedToStage(e:Event):void
		{
			const container:DisplayObjectContainer = e.target as DisplayObjectContainer;
			const type:Class = container["constructor"];
			const binding:ContainerBinding = _registry.getBinding(container);
			binding.handleView(container, type);
		}
		
	}

}